/*
 * Copyright (c) 2025 Alliedstar
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include <stdlib.h>

#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
// #include <zephyr/sys/printk.h>
#include <zephyr/logging/log.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/services/bas.h>

#include "ble.h"
#include "servo_motor.h"
#include "led.h"
#include "adc.h"
// #include <zephyr/bluetooth/hci.h>
// #include <zephyr/bluetooth/conn.h>
// #include <zephyr/settings/settings.h>

// #include <zephyr/types.h>
// #include <stddef.h>
// #include <string.h>
// #include <errno.h>

LOG_MODULE_REGISTER(BLE_MODULE, LOG_LEVEL_INF);

static bool is_connected = false;
static bool is_advertising = false;
static bool is_notification_enabled = false;

// static const struct bt_data ad[] = {
// 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	
// };

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)),
    // BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE),
};

static const struct bt_data sd[] = {
	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};

static void on_connected(struct bt_conn *conn, uint8_t ret)
{
    if (ret) {
        LOG_ERR("Connection failed: 0x%02x", ret);
        return;
    }
    
    is_connected = true;
    LOG_INF("PC connected");
    blink_stop();
}

static void on_disconnected(struct bt_conn *conn, uint8_t reason)
{
    is_connected = false;
    is_notification_enabled = false;
    is_advertising = false;

    blink_start();
    LOG_INF("PC disconnected: 0x%02x", reason);
}

BT_CONN_CB_DEFINE(conn_callbacks) = {
    .connected = on_connected,
    .disconnected = on_disconnected,
};

static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    is_notification_enabled = (value == BT_GATT_CCC_NOTIFY);
    LOG_INF("Notifications %s", is_notification_enabled ? "enabled" : "disabled");
}

static void send_data_to_pc(const uint8_t *data, uint16_t len)
{
    if (!is_connected || !is_notification_enabled) {
        LOG_WRN("Cannot send: PC not connected or notifications disabled");
        return;
    }

    int ret = bt_gatt_notify(NULL, 
                           bt_gatt_find_by_uuid(NULL, 0, BT_UUID_CUSTOM_TX),
                           data, len);
    
    if (ret) {
        LOG_ERR("Notify failed: %d", ret);
    } else {
        LOG_INF("Sent %u bytes to PC", len);
    }
}

static ssize_t ble_receive (struct bt_conn *conn,
                          const struct bt_gatt_attr *attr,
                          const void *buf, uint16_t len,
                          uint16_t offset, uint8_t flags)
{
    char str1[] = "start";
    char str2[] = "stop";

    LOG_INF("Received %u bytes and offset is %d\n", len, offset);
    
    if (strncmp(buf, str1, len) == 0) {
        LOG_INF("start\n");
        is_working = true;
        if (is_notification_enabled) {
            const char *response = "Received";
            send_data_to_pc(response, strlen(response));
        }
    }
    else if (strncmp(buf, str2, len) == 0) {
        LOG_INF("stop\n");
        is_working = false;
        if (is_notification_enabled) {
            const char *response = "Received";
            send_data_to_pc(response, strlen(response));
        }
    }
    else {
        LOG_INF("Unknown command\n");
    }

    return len;
}

BT_GATT_SERVICE_DEFINE(custom_service,
    // 主服务
    BT_GATT_PRIMARY_SERVICE(BT_UUID_CUSTOM_SERVICE),

    // TX特征（设备→电脑）- 支持通知
    BT_GATT_CHARACTERISTIC(BT_UUID_CUSTOM_TX,
                          BT_GATT_CHRC_NOTIFY,
                          BT_GATT_PERM_NONE,
                          NULL, NULL, NULL),
    BT_GATT_CCC(ccc_cfg_changed,
            BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),

    // RX特征（电脑→设备）- 支持写入
    BT_GATT_CHARACTERISTIC(BT_UUID_CUSTOM_RX,
                          BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                          BT_GATT_PERM_WRITE,
                          NULL, ble_receive, NULL),
);

static void start_advertising(void)
{
    int ret;

    const struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
						BT_LE_ADV_OPT_CONN,
						BT_GAP_ADV_FAST_INT_MIN_2,
						BT_GAP_ADV_FAST_INT_MAX_2,
						NULL);

    ret = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));

    // ret = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    if (ret) {
        LOG_ERR("Advertising failed: %d", ret);
        return;
    }

    is_advertising = true;

    LOG_INF("Advertising started. Waiting for PC connection...");
}

static void bt_ready(int ret)
{  
    if (ret) {
        LOG_ERR("Bluetooth init failed: %d", ret);
        return;
    }

    LOG_INF("Bluetooth initialized");

    // bt_bas_set_battery_level(88);
    start_advertising();
}

// static void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
// {
// 	LOG_INF("Updated MTU: TX: %d RX: %d bytes\n", tx, rx);
// }

// static struct bt_gatt_cb gatt_callbacks = {
// 	.att_mtu_updated = mtu_updated
// };

// static void hrs_ntf_changed(bool enabled)
// {
// 	hrf_ntf_enabled = enabled;

// 	printk("HRS notification status changed: %s\n",
// 	       enabled ? "enabled" : "disabled");
// }

// static struct bt_hrs_cb hrs_cb = {
// 	.ntf_changed = hrs_ntf_changed,
// };

// bt_hrs_cb_register(&hrs_cb);

static void bas_notify(uint8_t battery_level)
{
    uint8_t battery_level_old = 0;
    int ret;

    battery_level_old = bt_bas_get_battery_level();

    if (abs(battery_level_old - battery_level) > 1) {
	    ret = bt_bas_set_battery_level(battery_level);
        if (ret) {
            LOG_ERR("Set battery level failed: %d", ret);
            return;
        }
        LOG_INF("Update battery level");
        LOG_INF("battery_level_old: %d", battery_level_old);
        LOG_INF("battery_level: %d", battery_level);
    }
}

static uint8_t convert_voltage_to_level(uint16_t voltage_mv) 
{
    uint8_t battery_level = 0;

    if (voltage_mv >= 8200) {
        battery_level = 100;
    } else if (voltage_mv <= 7200) {
        battery_level = 0;
    } else {
        battery_level = 100 - (8200 - voltage_mv)/10;
    }
    
    return battery_level;
}

void thread_ble(void *p1, void *p2, void *p3)
{
    int ret;
    bool send_enable = false;
    uint8_t battery_level;

    ARG_UNUSED(p1);
	ARG_UNUSED(p2);
	ARG_UNUSED(p3);

    LOG_INF("thread_ble: thread start...\n");

    ret = bt_enable(bt_ready);
    if (ret) {
        LOG_ERR("Bluetooth enable failed: %d", ret);
        return;
    }

	// bt_gatt_cb_register(&gatt_callbacks);
    error_led_off();

    while (true) {

        if(!is_advertising) {
            start_advertising();
        }
        
        if(is_working) {
            send_enable = true;
        }

        if(is_done&send_enable) {
            if (is_connected && is_notification_enabled) {
                const char *response = "Done";
                send_data_to_pc(response, strlen(response));
            }
            send_enable = false;
        }

        if (value_is_ready && !is_working) {
            
            battery_level = convert_voltage_to_level(battery_voltage);
            
            if (battery_level <= 10) {
                error_led_on();
            }
            else {
                error_led_off();
            }

            if (is_connected) {
                bas_notify(battery_level);
            }
        }

        k_sleep(K_SECONDS(2));
    }
}